﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
namespace TagFlo
{
    public class HierarchyNode<T> where T : class
    {
        public T Entity { get; set; }
        public IEnumerable<HierarchyNode<T>> ChildNodes { get; set; }
        public int Depth { get; set; }
    }

    public class HierarchyPath
    {
        public Path Path { get; set; }
        public IEnumerable<HierarchyPath> Childs { get; set; }
        public int Depth { get; set; }
    }

    public static class LinqExtensionMethods
    {
       
        
        private static System.Collections.Generic.IEnumerable<HierarchyNode<TEntity>> CreateHierarchy<TEntity, TProperty>
          (IEnumerable<TEntity> allItems, TEntity parentItem,
          Func<TEntity, TProperty> parentProperty, int depth) where TEntity : class
        {
            IEnumerable<TEntity> childs;
            
            if (parentItem == null) 
                childs = allItems.Where(i => parentProperty(i).Equals(default(TEntity)));
            else
                childs = allItems.Where(i => parentProperty(i).Equals(parentItem));

            if (childs.Count() > 0)
            {
                depth++;

                foreach (var item in childs)
                    yield return new HierarchyNode<TEntity>()
                    {
                        Entity = item,
                        ChildNodes = CreateHierarchy<TEntity, TProperty>
                            (allItems, item,  parentProperty, depth),
                        Depth = depth
                    };
            }
        }


        private static IEnumerable<HierarchyPath> GetPathHierarchy(IEnumerable<Path> allItems, Path parentItem) 
        {
             Path parent = null;
 
  if (parentItem != null)
    parent = parentItem;
 
  var childPaths = allItems.Where(p => p.Parent == parent);
 
  Collection<HierarchyPath> hierarchy = new Collection<HierarchyPath>();
 
  foreach (var p in childPaths)
    hierarchy.Add(new HierarchyPath() { Path = p, Childs = GetPathHierarchy(allItems, p) });
 
  return hierarchy;
}



        /// <summary>
        /// LINQ IEnumerable AsHierachy() extension method
        /// </summary>
        /// <typeparam name="TEntity">Entity class</typeparam>
        /// <typeparam name="TProperty">Property of entity class</typeparam>
        /// <param name="allItems">Flat collection of entities</param>
        /// <param name="idProperty">Reference to Id/Key of entity</param>
        /// <param name="parentIdProperty">Reference to parent Id/Key</param>
        /// <returns>Hierarchical structure of entities</returns>
        public static System.Collections.Generic.IEnumerable<HierarchyNode<TEntity>> AsHierarchy<TEntity, TProperty>
          (this IEnumerable<TEntity> allItems, Func<TEntity, TProperty> parentProperty)
          where TEntity : class
        {
            return CreateHierarchy(allItems, default(TEntity),  parentProperty, 0);
        }

        public static IEnumerable<HierarchyPath> AsPathHierarchy(this IEnumerable<TagFlo.Path> allItems)
          
        {
            return GetPathHierarchy(allItems, default(Path));
        }
    }

}
